package com.xiaobaibai.server.blog;

import com.alibaba.fastjson.JSON;
import com.qiniu.util.Auth;
import com.xiaobaibai.common.Common;
import com.xiaobaibai.dao.BlogDao;
import com.xiaobaibai.dao.LabelDao;
import com.xiaobaibai.es.IEsService;
import com.xiaobaibai.pojo.Blog;
import com.xiaobaibai.pojo.Label;
import com.xiaobaibai.units.QiniuUnit;
import com.xiaobaibai.vo.BlogArticle;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class BlogServiceImpl implements IBlogService {

    @Autowired
    private BlogDao blogDao;

    @Autowired
    private LabelDao labelDao;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    IEsService esService;

    @Autowired
    private QiniuUnit qiniuUnit;

    @Override
    //value组名  key里面的个体名
    @Cacheable(value = "blogList",key = "")//将方法运行的结果进行缓存，以后再获取相同的数据时，直接从缓存中获取，不再调用方法
    public List<Blog> getBlogList() {
        List<Blog> blogList = blogDao.getAllBlogList();
        List<Blog> offBlog=new ArrayList<>();
        List<Blog> result=new ArrayList<>(blogList.size());
        for (Blog blog : blogList) {
            if(!blog.getMyStatus()){
                //不是上架
                offBlog.add(blog);
            }else{//上架
                result.add(blog);
            }
        }

        result.addAll(offBlog);
        Collections.reverse(result);

        return result;
    }

    @Override
    //还可以指定 value+key  仅删除目标组里面的一个个体
    @CacheEvict(value = "blogList",allEntries=true)//allEntries=true清除blogList缓存组里的所有缓存
    public void changStatus(String blogId, String status) {
        if(status.equals("1")){
            //将改为上架
            stringRedisTemplate.opsForSet().remove("offBlog",blogId);
        }else{
            //将改为下架
            stringRedisTemplate.opsForSet().add("offBlog",blogId);
        }
        blogDao.updateStatus(blogId,status);
    }

    @Override
    public String getQiniuToken() {
        Auth auth = Auth.create(Common.accessKey, Common.secretKey);
        return auth.uploadToken(Common.bucket);
    }

    @Override
    public List<Label> getAllLabel() {
        String allLabel = stringRedisTemplate.opsForValue().get("AllLabel");
        List<Label> labelList;
        if(allLabel==null)
            labelList = labelDao.getAllLabel();
        else
            labelList = JSON.parseArray(allLabel, Label.class);
        return labelList;
    }

    @Override
    @CacheEvict(value = "blogList",allEntries=true)
    public boolean deleteBlog(Integer blogId) {
        //一删除的话,缓存得大改,并且我也不会删除之前发布过的文章,所以只支持删除最后面的用于测试
        String blogCount = stringRedisTemplate.opsForValue().get("BlogCount");
        if(!blogCount.equals(blogId.toString()))
            return false;
        Blog blog = blogDao.selectByPrimaryKey(blogId);//先查后删
        blogDao.deleteByPrimaryKey(blogId);
        blogDao.setINCREMENT(Integer.parseInt(blogCount)-1);
        qiniuUnit.deleteQiniu(blog);
        deleteRedis(blogId);
        deleteEs(blogId);
        return true;
    }

    @Override
    @CacheEvict(value = "blogList",allEntries=true)
    public void saveBlog(Blog blog) {
        //对象里存入后就会有id了
        blog.setStatus(true);
        blogDao.insertSelective(blog);
        saveRedis(blog);
        saveEs(blog);
    }

    @Override
    @CacheEvict(value = "blogList",allEntries=true)
    public void saveDraft(Blog blog) {
        blog.setStatus(false);
        //保存草稿,就是别人看不到内容而已,除了内容其他都得填好来
        blogDao.insertSelective(blog);
        saveRedis(blog);
        saveEs(blog);
    }

    @Override
    @CacheEvict(value = "blogList",allEntries=true)
    public void updateBlog(Blog blog) {
        blogDao.updateByPrimaryKeySelective(blog);
        updateRedisByUpdate(blog);
        updateEs(blog);
    }

    @Override
    public Blog getBlogById(String blogId) {
        Blog blog = blogDao.selectByPrimaryKey(Integer.parseInt(blogId));
        return blog;
    }

    private void saveRedis(Blog blog){
        Long blogCount = stringRedisTemplate.opsForValue().increment("BlogCount");
        int o= (int) (blogCount/10);
        BlogArticle blogArticle=getBlogArticle(blog);
        redisTemplate.opsForValue().set("blogCache:"+blogCount.intValue(),blogArticle);
        stringRedisTemplate.executePipelined(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                for(int i=1;i<=o+1;i++) {//随便加个1,避免出错
                    redisOperations.delete("pageNumMap:"+o);
                }
                return null;
            }
        });
    }

    private void updateRedisByUpdate(Blog blog){
        BlogArticle blogArticle=getBlogArticle(blog);
        redisTemplate.opsForValue().set("blogCache:"+blogArticle.getId(),blogArticle);
        stringRedisTemplate.opsForValue().set("blogContentCache:"+blogArticle.getId(),
                blog.getContent());
    }

    private void saveEs(Blog blog){
        BlogArticle blogArticle=getBlogArticle(blog);
        esService.addDoc(blogArticle);
    }

    private void updateEs(Blog blog){
        BlogArticle blogArticle=getBlogArticle(blog);
        esService.updateDoc(blogArticle);
    }

    private void deleteEs(Integer blogId){
        esService.deleteDoc(blogId.toString());
    }

    private void deleteRedis(Integer blogId){
        stringRedisTemplate.executePipelined(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                stringRedisTemplate.opsForValue().increment("BlogCount",-1);
                stringRedisTemplate.delete("blogContentCache:"+blogId);
                stringRedisTemplate.delete("blogCache:"+blogId);
                return null;
            }
        });
    }

    private BlogArticle getBlogArticle(Blog blog){
        BlogArticle blogArticle=new BlogArticle();
        blogArticle.setId(blog.getId());//这里因为是新增的id就是顺着来
        blogArticle.setComment(0);
        blogArticle.setLove(0);
        blogArticle.setExamine(0);
        blogArticle.setOverview(blog.getOverview());
        blogArticle.setCreate_time(DateFormatUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
        blogArticle.setImage(blog.getImage());
        blogArticle.setLabel_id(blog.getLabelId());
        blogArticle.setTag(blog.getTag());//mysql里面默认的测试小标签
        blogArticle.setTitle(blog.getTitle());
        return blogArticle;
    }

}
